package org.NooLab.itexx.co;


import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.NooLab.itexx.ITexx;
import org.NooLab.itexx.ITexxFactory;
import org.NooLab.itexx.comm.tcp.box.TcpBox;
import org.NooLab.itexx.comm.tcp.box.infra.DataSenderIntf;
import org.NooLab.utilities.logging.PrintLog;

import jlibs.core.lang.JavaProcessBuilder;

public class CoWorker implements CoWorkerIntf{

	ITexxFactory itxFactory;
	ITexx itexx;
		
	
	String name = "";
	private String guid = "";
	private Process process;
	
	int priority = 4;
	int startingOrder = 0 ;
	
	String instanceGuid = "";
	int proposedPort =0;
	int effectiveClientPort = 0;
	private int tikaServerPort;
	
	
	int status = CoWorkerIntf._CO_STATUS_UNKNOWN ;
	long startingSince = 0L;
	
	DataSenderIntf sender = null;
	
	// ......................
	
	JavaProcessBuilder jvm;
	
	int initialHeap;
	int maxHeap ;
	
	String jarFilename="" , mainClass="";
	String jarFilePath="", appWorkingDir="";
	String extLibPath="";

	
	ArrayList<String> classPaths = new ArrayList<String> ();
	ArrayList<String> extLibPaths = new ArrayList<String> ();
	ArrayList<String> extraClassPath = new ArrayList<String> ();
	
	ArrayList<String> arguments = new ArrayList<String> (); 
	
	int exitValue;
	// ......................
	
	// UDP
	
	// Map<String,String> params = new HashMap<String, String>() ;
	
	//
	
	CoWorkers parent;
	
	
	boolean created =false;
	
	PrintLog out;
	
	 

	// ========================================================================
	public CoWorker( CoWorkers parent, ITexx itx) {
		
		this.parent = parent;
		itxFactory = parent.itxFactory ;
		itexx = itx;
		
		this.out = parent.out;
	}
	// ========================================================================
	
	
	class Launcher implements Runnable{

		
		public Launcher(){
			
		}
		
		public void start(){
			
		}
		@Override
		public void run() {
			 
			try {
				
				launch() ;
				
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		
		
	} // class 
	
	public void launch() throws Exception{
		
		if (created ==false){
			return;
		}
		// to get the created command:
		String command[] = jvm.command();

		process = jvm.launch(System.out, System.err);
		out.delay(500);
		// to launch it
		
		 //Read out dir output
        InputStream is = process.getInputStream();
        
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        String line;
        
        System.out.printf("Output of running %s is:\n",  Arrays.toString(command));
        
        String processName = getArgumentValueStr( arguments, "-name"); 
        
        while ((line = br.readLine()) != null) {
        	
        	if (line.contains("@iTexx")){
        		new CoWorkerMsgDigest( itexx,this, CoWorkerIntf._mainServerPort, line);
        	}else{
        		System.out.println(line);
        	}
        }
		
		//Wait to get exit value
        try {

        	exitValue = process.waitFor();
            
            System.out.println("\n\nExit Value of process <"+processName+"> is "+exitValue);
            												
        } catch (Exception e) {
            e.printStackTrace();
        }
	}
	

	/**
	 * returns the complete argument as defined in processDef (type = ExtWorker)
	 * 
	 * @param string
	 * @return
	 */
	public String getArgumentByTopic(String topic) {
		String completeArg="" ;
		
		for (int i=0;i<arguments.size();i++){
			String str = arguments.get(i) ;
			
			if (str.startsWith(topic.trim())){
				completeArg = str ;  
				break;
			}
			
		}//i->
		
		return completeArg;
	}
	
	private String getArgumentValueStr( ArrayList<String> args, String marker) {
	
		String avStr="",str;
		
		for (int i=0;i<args.size();i++){
			if (args.get(i).trim().startsWith(marker)){
				str = args.get(i).trim();
				if (str.indexOf(":")>2){
					avStr = str.split(":")[1];
				}
				break;
			}
		}
		return avStr;
	}


	public void sendRelease( int port) {
		
		String releaseMsg="" ;
		TcpBox tcpBox = new TcpBox ();
		
		DataSenderIntf adhocSender = tcpBox.createSender( port, CoWorkerIntf._mainServerPort, "");
		
		try {
			 
			releaseMsg = "<action start=\"1\" mode=\"release\" >\n<process name=\"\" secret=\""+instanceGuid+"\">";
			
			adhocSender.send(releaseMsg) ;
		
			out.delay( 300 ) ;
			
			adhocSender.release() ;
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}


	public void create() throws IOException{
		
		jvm = new JavaProcessBuilder();
		
		jvm.initialHeap(512); // or jvm.initialHeap("512m");
		jvm.maxHeap(1424); // or jvm.maxHeap("1024m");
		 
		
		
		jvm.workingDir(new File(appWorkingDir));
		
		String jarCP = parent.fileutil.createpath(jarFilePath, jarFilename) ;
		jvm.classpath( new File(jarCP)) ; // relative path from configured working dir
		
		// jvm.classpath( classPaths );
		// jvm.libraryPath( new File(jarFilePath)) ; // 
		
		jvm.extDir(new File(extLibPath));
		for (int i=0;i<extLibPaths.size();i++){
			jvm.libraryPath(new File(extLibPaths.get(i)));
		}
		jvm.endorsedDir(new File(extLibPath));
		
		List<File> classpath = jvm.classpath();
		for (int i=0;i<classpath.size();i++){
			// parent.out.print(2, classpath.get(i).getAbsolutePath() ) ;
		}
		
		// to configure mainclass and its arguments
		jvm = jvm.mainClass(mainClass);// "example.MyTest") ;x
		
		// jvm.arg("-xvf");
		// jvm.arg("testDir");
		for (int i=0;i<arguments.size();i++){
			jvm.arg( arguments.get(i) );
		}
		
		created = true;
		
	}

	// ------------------------------------------------------------------------s

	public void setMainClass(String mainclass) {
		 
		mainClass = mainclass;
	}


	public void setJarFilename(String jarfilename) {
		// 
		jarFilename = jarfilename;
	}


	public void setJarFilePath(String jarfilepath) {
		// 
		jarFilePath = parent.fileutil.createpath(itxFactory.getSystemRootDir(), jarfilepath);
		// jarFilePath = jarfilepath;
	}


	public void setAppWorkingDir(String dir) {
		 
		appWorkingDir = dir;
	}


	public void setExtLibrariesPath(String libfolder) {
		// 
		extLibPath = libfolder ;

		extLibPaths.clear();
		extLibPaths.add(extLibPath);
	}


	public void addExtLibrariesPath(String string) {
		
		extLibPaths.add(extLibPath);
	}


	public String getName() {
		return name;
	}


	public void setName(String name) {
		this.name = name;
	}


	public int getInitialHeap() {
		return initialHeap;
	}


	public void setInitialHeap(int initialHeap) {
		this.initialHeap = initialHeap;
	}


	public int getMaxHeap() {
		return maxHeap;
	}


	public void setMaxHeap(int maxHeap) {
		this.maxHeap = maxHeap;
	}


	public String getGuid() {
		return guid;
	}


	public void setGuid(String guid) {
		this.guid = guid;
	}


	public Process getProcess() {
		return process;
	}


	public PrintLog getOut() {
		return out;
	}


	public void addArgument(String arg) {

		arguments.add(arg);
		
	}


	public ArrayList<String> getClassPaths() {
		return classPaths;
	}


	public void addExtraClassPath(String classpath) {

		extraClassPath.add(classpath) ;
		
	}


	public void setInstanceGuid(String guid) {
		// 
		instanceGuid = guid;
	}


	public String getInstanceGuid() {
		return instanceGuid;
	}


	public void setTikaServerPort(int tikaserverport) {
		tikaServerPort = tikaserverport;
	}
	public int getTikaServerPort() {
		return tikaServerPort;
	}


	public void setProposedPort(int port) {
		proposedPort = port;
	}
	public int getProposedPort() {
		return proposedPort ;
	}


	public int getEffectiveClientPort() {
		return effectiveClientPort;
	}


	public void setEffectiveClientPort(int srvPort, int port) {
		
		if (port>1100){
			
			effectiveClientPort = port;
			
			TcpBox tcpBox = new TcpBox();
		 
			sender = tcpBox.createSender( port, srvPort, "") ;
		}
	}


	public int getStatus() {
		return status;
	}


	public void setStatus(int stateval) {
		status = stateval;
		
		if (status==CoWorkerIntf._CO_STATUS_STARTING){
			startingSince = System.currentTimeMillis() ;
		}
		
	}


	public void showArguments() {
		// ArrayList<String> arguments
		
		out.print(2, "\nLaunching CoWorker <"+name+"> with arguments ...");
		
		for (int i=0;i<arguments.size();i++){
			out.print(2, "   "+arguments.get(i));
		}// i->
		
		out.print(2, "\n\n");
		
	}


	public void stop() {
		// TODO Auto-generated method stub
		
	}
	
}
